package server;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
 * This class is in charge of handling a single connection - receiving the request in stream, passing it to a tokenizer for parsing
 * and then to the protocol for processing. once the response has been sent, the socket is closed
 * @author yariv zur
 */

class ConnectionHandler implements Runnable  {
	private OutputStream out;
	private InputStream in;
	private Request request;
	Socket clientSocket;
	ServerProtocol protocol;
	Tokenizer _tok;
	/**
	 * Constructor for the ConnectionHandler class
	 * @param acceptedSocket - the client/employee socket to receive/send data
	 * @param p - the protocol to process requests (in this case, MessageHandler)
	 * @param tok - the tokenizer to parse the request with
	 */
	public ConnectionHandler(Socket acceptedSocket, ServerProtocol p, Tokenizer tok) {
		out = null;
		clientSocket = acceptedSocket;
		protocol = p;
		_tok = tok;
		System.out.println("Accepted connection from client!");
		System.out.println("The client is from: " +acceptedSocket.getInetAddress() + ":" + acceptedSocket.getPort());
	}
	/**
	 * This method asks the tokenizer for the next token (request) and hands it to the protocol for processing
	 * if the tokenizer or stream are closed, an Exception will be thrown and the function will return
	 */
	public void process(){
		try{
			request = _tok.nextToken();
		}
		catch(IOException e){
			System.out.println("The tokenizer is not ready");
			return;
		}
		byte[] response = protocol.processMessage(request); //pass the parsed request to the protocol for processing and receive a response
		if(response != null){
			try {
				out.write(response);
			} catch (IOException e) {
				System.out.println("Could not write response to client!");
			}
		}

	}

	/**
	 * initializes the input & output streams from the socket
	 * @throws IOException
	 */
	public void initialize() throws IOException { // Initialize I/O
		in = clientSocket.getInputStream();
		out = clientSocket.getOutputStream();
	}

	/**
	 * Closes the connection to the client
	 */
	public void close() {
		try {
			if (in != null) {
				in.close();
			}
			if (out != null) {
				out.close();
			}
			clientSocket.close();
		} catch (IOException e) {
			System.out.println("Exception in closing I/O");
		}
	}
	/**
	 * the main function of the ConnectionHandler:
	 * 1. initialize the communication infrastructure
	 * 2. process a message
	 * 3. close the connection
	 */
	public void run() {
		try {
			initialize();
		} catch (IOException e) {
			System.out.println("Error in initializing I/O");
		}
		process();

		System.out.println("Connection closed - bye bye...");
		close();
	}
}